This example notebook is associated to the paper:
Delforge, D., Muñoz-Carpena, R., Van Camp, M. Vanclooster, M. (2020), A parsimonious empirical approach to streamflow recession analysis and forecasting, accepted at Water Resource Research (9-01-2020)
The notebook illustrates how to make one-day-ahead forecast of the recession using EDM-Simplex.
import pandas as pd # data manipulation
import numpy as np # numeric computation
import matplotlib.pyplot as plt # plotting library
import edm_cmd as edm
# Python and Package version used in this notebook or in the edm code
import sys
import scipy as sc
import matplotlib as mpl
print("The Python version is %s.%s.%s" % sys.version_info[:3])
print(f"Pandas {pd.__version__}")
print(f"Numpy {np.__version__}")
print(f"Scipy {sc.__version__}")
print(f"Matplotlib {mpl.__version__}")
We load the streamflow time series for station S1, the upstream station Lhomme river watershed. We will forecast the recession points the points associated with the BRU method for station S1. We also define the library of potential nearest-neighbor states that will serve as a basis to forecast the BRU recession points. This library contains all decreasing streamflow points that keep decreasing up to the forecast horizon.
tp = 1 # day (forecast horizon)
ts = pd.read_csv('streamflow_data.csv', parse_dates=True, index_col=0, usecols=[0,1])
rdf = pd.read_csv('recession_df.csv', parse_dates=True, index_col=0)
lib_bin = rdf[f'DSF.S1'] # Spot negative dQ_dt (DSF = decreasing streamflow)
# The edm.segmentation method turns the 1D binary array of recession into a 2D
# array tracking the start and the end of each recession segments
lib_seg = edm.segmentation(lib_bin)
lib_trunc = lib_seg
lib_trunc[:, 1] = lib_trunc[:, 1] - tp
# overwrite lib_bin for plot
lib_bin = edm.binarization(lib_trunc, len(lib_bin))
fig = plt.figure()
ax = fig.gca()
ax.plot(ts, label='S1 hydrograph')
ax.plot(ts[lib_bin], '.', label='LIB states', ms=3)
ax.plot(ts[rdf['BRU.S1']], '.', label='BRU recession points')
ax.legend()
_ = ax.set_ylabel('Daily mean streamflow (m³/s)')
col=0
data = ts.values
m=2 # embedding dimension
tp = 1
# The reference states are those 1 day before the forecast day
pred_seg = edm.segmentation(rdf[f'BRU.S1']) # predicted segments
# uncomment these lines to truncate the head of recession segments by h
# pred_trunc = pred_seg
# pred_trunc[:, 0] = pred_trunc[:, 0] + h
# mask = pred_trunc[:, 0] <= pred_trunc[:, 1]
# pred_seg = pred_trunc[mask]
ref_seg = pred_seg - tp # reference segments
x_pred, x_true = edm.ConvergentCrossMapping(data, col, col,
ref=ref_seg,
lib=lib_trunc,
lib_sizes=[200],
n_samples=200,
m=m,
tp=tp,
tw=10)
nse = edm.NashAndSutcliffeEfficency(x_obs=x_true, x_sim=np.median(x_pred, axis=1))
print(f'Nash & Sutcliffe Efficiency: {nse}')
fig = plt.figure()
ax = fig.gca()
ax.plot(x_true, np.median(x_pred, axis=1), '.')
ax.set_xlabel('True recession points [m³/s]')
ax.set_ylabel('Median forecast [m³/s]')
ax.set_aspect('equal')